* elminiate some early program exits.
exits without cleanup make it harder to find memory leaks.
fix a few leaks.
enhance random format to support reading real time position data.
correct some sign related warnings.
* use invariant generator for random format.
* make compilers happy with random.
clang doesn't like:
random.cc:61:42: note: read of non-constexpr variable 'generator' is not allowed in a constant expression
constexpr double scalefactor = 1.0 / (*generator).max();
msvc doesn't like:
warning C4100: 'fname': unreferenced formal parameter
* catch main.cc up with master manually.
posndata
} gpsdata_type;
-#define NOTHINGMASK 0
-#define WPTDATAMASK 1
-#define TRKDATAMASK 2
-#define RTEDATAMASK 4
-#define POSNDATAMASK 8
+#define NOTHINGMASK 0U
+#define WPTDATAMASK 1U
+#define TRKDATAMASK 2U
+#define RTEDATAMASK 4U
+#define POSNDATAMASK 8U
/* mask objective testing */
#define doing_nothing (global_opts.masked_objective == NOTHINGMASK)
Waypoint();
~Waypoint();
Waypoint(const Waypoint& other);
- // the default assignment operator is not appropriate as we do deep copy of some members,
- // and we haven't bothered to write an appropriate one.
- // Catch attempts to use the default assignment operator.
- Waypoint& operator=(const Waypoint& other) = delete;
+ Waypoint& operator=(const Waypoint& other);
bool HasUrlLink() const;
const UrlLink& GetUrlLink() const;
/* REQUIRED means that the option is required to be set.
* See also BEGIN/END_REQ */
-#define ARGTYPE_REQUIRED 0x40000000
+#define ARGTYPE_REQUIRED 0x40000000U
/* HIDDEN means that the option does not appear in help texts. Useful
* for debugging or testing options */
-#define ARGTYPE_HIDDEN 0x20000000
+#define ARGTYPE_HIDDEN 0x20000000U
/* BEGIN/END_EXCL mark the beginning and end of an exclusive range of
* options. No more than one of the options in the range may be selected
* or set. If exactly one must be set, use with BEGIN/END_REQ
* Both of these flags set is just like neither set, so avoid doing that. */
-#define ARGTYPE_BEGIN_EXCL 0x10000000
-#define ARGTYPE_END_EXCL 0x08000000
+#define ARGTYPE_BEGIN_EXCL 0x10000000U
+#define ARGTYPE_END_EXCL 0x08000000U
/* BEGIN/END_REQ mark the beginning and end of a required range of
* options. One or more of the options in the range MUST be selected or set.
* If exactly one must be set, use with BEGIN/END_EXCL
* Both of these flags set is synonymous with REQUIRED, so use that instead
* for "groups" of exactly one option. */
-#define ARGTYPE_BEGIN_REQ 0x04000000
-#define ARGTYPE_END_REQ 0x02000000
+#define ARGTYPE_BEGIN_REQ 0x04000000U
+#define ARGTYPE_END_REQ 0x02000000U
-#define ARGTYPE_TYPEMASK 0x00000fff
-#define ARGTYPE_FLAGMASK 0xfffff000
+#define ARGTYPE_TYPEMASK 0x00000fffU
+#define ARGTYPE_FLAGMASK 0xfffff000U
#define ARG_NOMINMAX NULL, NULL
#define ARG_TERMINATOR {0, 0, 0, 0, 0, ARG_NOMINMAX, NULL}
void init_vecs();
void exit_vecs();
void disp_formats(int version);
-const char* name_option(long type);
+const char* name_option(uint32_t type);
void printposn(double c, int is_lat);
void* xcalloc(size_t nmemb, size_t size);
*/
-#include <QtCore/QCoreApplication>
-#include <QtCore/QStack>
-#include <QtCore/QString>
-#include <QtCore/QTextCodec>
-#include <QtCore/QTextStream>
-
-#include "cet.h"
-#include "cet_util.h"
-#include "csv_util.h"
-#include "defs.h"
-#include "filterdefs.h"
-#include "inifile.h"
-#include "session.h"
-#include "src/core/file.h"
-#include "src/core/usasciicodec.h"
-#include <cctype>
-#include <clocale>
-#include <cstdio>
-#include <cstdlib>
-#include <csignal>
+#include <clocale> // for setlocale, LC_NUMERIC, LC_TIME
+#include <csignal> // for signal, SIGINT, SIG_ERR
+#include <cstdio> // for printf, fgetc, stdin
+#include <cstdlib> // for exit
+#include <cstring> // for strcmp
+#include <ctime> // for time
+
+#include <QtCore/QByteArray> // for QByteArray
+#include <QtCore/QChar> // for QChar
+#include <QtCore/QCoreApplication> // for QCoreApplication
+#include <QtCore/QFile> // for QFile
+#include <QtCore/QIODevice> // for QIODevice::ReadOnly
+#include <QtCore/QLocale> // for QLocale
+#include <QtCore/QStack> // for QStack
+#include <QtCore/QString> // for QString
+#include <QtCore/QStringList> // for QStringList
+#include <QtCore/QSysInfo> // for QSysInfo
+#include <QtCore/QTextCodec> // for QTextCodec
+#include <QtCore/QTextStream> // for QTextStream
+#include <QtCore/QtConfig> // for QT_VERSION_STR
+#include <QtCore/QtGlobal> // for qPrintable, qVersion, QT_VERSION, QT_VERSION_CHECK
+
#ifdef AFL_INPUT_FUZZING
#include "argv-fuzz-inl.h"
#endif
+#include "defs.h"
+#include "cet_util.h" // for cet_convert_init, cet_convert_strings, cet_convert_deinit, cet_deregister, cet_register, cet_cs_vec_utf8
+#include "csv_util.h" // for csv_lineparse
+#include "filter.h" // for Filter
+#include "filterdefs.h" // for disp_filter_vec, disp_filter_vecs, disp_filters, exit_filter_vecs, find_filter_vec, free_filter_vec, init_filter_vecs
+#include "inifile.h" // for inifile_done, inifile_init
+#include "queue.h" // for queue
+#include "session.h" // for start_session, session_exit, session_init
+#include "src/core/datetime.h" // for DateTime
+#include "src/core/file.h" // for File
+#include "src/core/usasciicodec.h" // for UsAsciiCodec
+
#define MYNAME "main"
// be careful not to advance argn passed the end of the list, i.e. ensure argn < qargs.size()
#define FETCH_OPTARG qargs.at(argn).size() > 2 ? QString(qargs.at(argn)).remove(0,2) : qargs.size()>(argn+1) ? qargs.at(++argn) : QString()
-void signal_handler(int sig);
-
class QargStackElement
{
public:
"\n");
}
-int
-main(int argc, char* argv[])
+static void
+signal_handler(int sig)
+{
+ (void)sig;
+ tracking_status.request_terminate = 1;
+}
+
+static int
+run(const char* prog_name)
{
-#ifdef AFL_INPUT_FUZZING
- AFL_INIT_ARGV();
-#endif
int c;
int argn;
ff_vecs_t* ivecs = nullptr;
const char* ovec_opts = nullptr;
const char* fvec_opts = nullptr;
int opt_version = 0;
- int did_something = 0;
- const char* prog_name = argv[0]; /* argv is modified during processing */
+ bool did_something = false;
queue* wpt_head_bak, *rte_head_bak, *trk_head_bak; /* #ifdef UTF8_SUPPORT */
signed int wpt_ct_bak, rte_ct_bak, trk_ct_bak; /* #ifdef UTF8_SUPPORT */
- QStack<QargStackElement> qargs_stack = QStack<QargStackElement>();
+ QStack<QargStackElement> qargs_stack;
- // Create a QCoreApplication object to handle application initialization.
- // In addition to being useful for argument decoding, the creation of a
- // QCoreApplication object gets Qt initialized, especially locale related
- // QTextCodec stuff.
- // For example, this will get the QTextCodec::codecForLocale set
- // correctly.
- QCoreApplication app(argc, argv);
// Use QCoreApplication::arguments() to process the command line.
QStringList qargs = QCoreApplication::arguments();
- (void) new gpsbabel::UsAsciiCodec(); /* make sure a US-ASCII codec is available */
-
-// MIN_QT_VERSION in configure.ac should correspond to the QT_VERSION_CHECK arguments in main.cc and gui/main.cc
-#if (QT_VERSION < QT_VERSION_CHECK(5, 9, 0))
-#error This version of Qt is not supported.
-#endif
-
- // The first invocation of QTextCodec::codecForLocale() may result in LC_ALL being set to the native environment
- // as opposed to the initial default "C" locale.
- // This was demonstrated with Qt5 on Mac OS X.
- // TODO: This need to invoke QTextCodec::codecForLocale() may be taken care of
- // by creating a QCoreApplication.
-#ifdef DEBUG_LOCALE
- printf("Initial locale: %s\n",setlocale(LC_ALL, NULL));
-#endif
- (void) QTextCodec::codecForLocale();
-#ifdef DEBUG_LOCALE
- printf("Locale after codedForLocale: %s\n",setlocale(LC_ALL, NULL));
-#endif
- // As recommended in QCoreApplication reset the locale to the default.
- // Note the documentation says to set LC_NUMERIC, but QCoreApplicationPrivate::initLocale()
- // actually sets LC_ALL.
- // Perhaps we should restore LC_ALL instead of only LC_NUMERIC.
- if (strcmp(setlocale(LC_NUMERIC,nullptr), "C") != 0) {
-#ifdef DEBUG_LOCALE
- printf("Resetting LC_NUMERIC\n");
-#endif
- setlocale(LC_NUMERIC,"C");
-#ifdef DEBUG_LOCALE
- printf("LC_ALL: %s\n",setlocale(LC_ALL, NULL));
-#endif
- }
- /* reset LC_TIME for strftime */
- if (strcmp(setlocale(LC_TIME,nullptr), "C") != 0) {
-#ifdef DEBUG_LOCALE
- printf("Resetting LC_TIME\n");
-#endif
- setlocale(LC_TIME,"C");
-#ifdef DEBUG_LOCALE
- printf("LC_ALL: %s\n",setlocale(LC_ALL, NULL));
-#endif
- }
-
- global_opts.objective = wptdata;
- global_opts.masked_objective = NOTHINGMASK; /* this makes the default mask behaviour slightly different */
- global_opts.charset_name.clear();
- global_opts.inifile = nullptr;
-
- gpsbabel_now = time(nullptr); /* gpsbabel startup-time */
- gpsbabel_time = current_time().toTime_t(); /* same like gpsbabel_now, but freezed to zero during testo */
-
- if (gpsbabel_time != 0) { /* within testo ? */
- global_opts.inifile = inifile_init(QString(), MYNAME);
- }
-
- init_vecs();
- init_filter_vecs();
- cet_register();
- session_init();
- waypt_init();
- route_init();
-
if (qargs.size() < 2) {
usage(prog_name,1);
- exit(0);
+ return 0;
}
/*
if (qargs.at(argn).size() > 2 && qargs.at(argn).at(2).toLatin1() == 'V') {
print_extended_info();
}
- exit(0);
+ return 0;
}
if (qargs.at(argn).size() > 1 && (qargs.at(argn).at(1).toLatin1() == '?' || qargs.at(argn).at(1).toLatin1() == 'h')) {
} else {
usage(prog_name,0);
}
- exit(0);
+ return 0;
}
c = qargs.at(argn).size() > 1 ? qargs.at(argn).at(1).toLatin1() : '\0';
fatal("Format does not support reading.\n");
}
if (global_opts.masked_objective & POSNDATAMASK) {
- did_something = 1;
+ did_something = true;
break;
}
/* simulates the default behaviour of waypoints */
cet_convert_strings(global_opts.charset, nullptr, nullptr);
cet_convert_deinit();
- did_something = 1;
+ did_something = true;
break;
case 'F':
optarg = FETCH_OPTARG;
*/
case '^':
disp_formats(opt_version);
- exit(0);
+ return 0;
case '%':
disp_filters(opt_version);
- exit(0);
+ return 0;
case 'h':
case '?':
usage(prog_name,0);
- exit(0);
+ return 0;
case 'p':
optarg = FETCH_OPTARG;
inifile_done(global_opts.inifile);
if (qargs.size() > 2) {
fatal("Extra arguments on command line\n");
} else if ((!qargs.isEmpty()) && ivecs) {
- did_something = 1;
+ did_something = true;
/* simulates the default behaviour of waypoints */
if (doing_nothing) {
global_opts.masked_objective |= WPTDATAMASK;
}
} else if (!qargs.isEmpty()) {
usage(prog_name,0);
- exit(0);
+ return 0;
}
if (ovecs == nullptr) {
/*
if (ovecs && ovecs->position_ops.wr_deinit) {
ovecs->position_ops.wr_deinit();
}
- exit(0);
+ return 0;
}
fatal("Nothing to do! Use '%s -h' for command-line options.\n", prog_name);
}
+ return 0;
+}
+
+int
+main(int argc, char* argv[])
+{
+#ifdef AFL_INPUT_FUZZING
+ AFL_INIT_ARGV();
+#endif
+ int rc = 0;
+ const char* prog_name = argv[0]; /* may not match QCoreApplication::arguments().at(0)! */
+
+// MIN_QT_VERSION in configure.ac should correspond to the QT_VERSION_CHECK arguments in main.cc and gui/main.cc
+#if (QT_VERSION < QT_VERSION_CHECK(5, 9, 0))
+#error This version of Qt is not supported.
+#endif
+
+#ifdef DEBUG_LOCALE
+ printf("Initial locale: %s\n",setlocale(LC_ALL, NULL));
+#endif
+
+ // Create a QCoreApplication object to handle application initialization.
+ // In addition to being useful for argument decoding, the creation of a
+ // QCoreApplication object gets Qt initialized, especially locale related
+ // QTextCodec stuff.
+ // For example, this will get the QTextCodec::codecForLocale set
+ // correctly.
+ QCoreApplication app(argc, argv);
+
+ // The first invocation of QTextCodec::codecForLocale() or
+ // construction of QCoreApplication object
+ // may result in LC_ALL being set to the native environment
+ // as opposed to the initial default "C" locale.
+ // This was demonstrated with Qt5 on Mac OS X.
+#ifdef DEBUG_LOCALE
+ printf("Locale after initial setup: %s\n",setlocale(LC_ALL, NULL));
+#endif
+ // As recommended in QCoreApplication reset the locale to the default.
+ // Note the documentation says to set LC_NUMERIC, but QCoreApplicationPrivate::initLocale()
+ // actually sets LC_ALL.
+ // Perhaps we should restore LC_ALL instead of only LC_NUMERIC.
+ if (strcmp(setlocale(LC_NUMERIC,nullptr), "C") != 0) {
+#ifdef DEBUG_LOCALE
+ printf("Resetting LC_NUMERIC\n");
+#endif
+ setlocale(LC_NUMERIC,"C");
+#ifdef DEBUG_LOCALE
+ printf("LC_ALL: %s\n",setlocale(LC_ALL, NULL));
+#endif
+ }
+ /* reset LC_TIME for strftime */
+ if (strcmp(setlocale(LC_TIME,nullptr), "C") != 0) {
+#ifdef DEBUG_LOCALE
+ printf("Resetting LC_TIME\n");
+#endif
+ setlocale(LC_TIME,"C");
+#ifdef DEBUG_LOCALE
+ printf("LC_ALL: %s\n",setlocale(LC_ALL, NULL));
+#endif
+ }
+
+ (void) new gpsbabel::UsAsciiCodec(); /* make sure a US-ASCII codec is available */
+
+ global_opts.objective = wptdata;
+ global_opts.masked_objective = NOTHINGMASK; /* this makes the default mask behaviour slightly different */
+ global_opts.charset_name.clear();
+ global_opts.inifile = nullptr;
+
+ gpsbabel_now = time(nullptr); /* gpsbabel startup-time */
+ gpsbabel_time = current_time().toTime_t(); /* same like gpsbabel_now, but freezed to zero during testo */
+
+ if (gpsbabel_time != 0) { /* within testo ? */
+ global_opts.inifile = inifile_init(QString(), MYNAME);
+ }
+
+ init_vecs();
+ init_filter_vecs();
+ cet_register();
+ session_init();
+ waypt_init();
+ route_init();
+
+ rc = run(prog_name);
+
cet_deregister();
waypt_flush_all();
route_flush_all();
exit_filter_vecs();
inifile_done(global_opts.inifile);
- exit(0);
-}
-
-void signal_handler(int sig)
-{
- (void)sig;
- tracking_status.request_terminate = 1;
+ exit(rc);
}
int column = -1;
QString c = csv_lineparse(str, "|", "", column++);
- while (c != nullptr) {
+ while (!c.isNull()) {
switch (column) {
case 0: /* "-" */ /* unknown fields for the moment */
case 1: /* "-" */
}
wpt->longitude = wppos_to_dec(s);
waypt_add(wpt);
+
+ // continue reading until csv_lineparse returns null indicating all dynamic memory has been deallocated.
+ while (csv_lineparse(nullptr, "\\w", "", linecount));
}
}
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111 USA
*/
+#include <cstdlib> // for atoi
+#include <random> // for mt19937
+
+#include <QtCore/QDateTime> // for QDateTime
+#include <QtCore/QString> // for QString
+#include <QtCore/QThread> // for QThread
+
#include "defs.h"
-#include "garmin_fs.h"
-#include "jeeps/gpsmath.h"
-#include <cstdlib>
-#include <ctime>
+#include "garmin_fs.h" // for garmin_fs_t, GMSD_SET, garmin_fs_flags_t, garmin_fs_alloc
#define MYNAME "random"
-static char* opt_points, *opt_seed;
+static char* opt_points, *opt_seed, *opt_nodelay;
static arglist_t random_args[] = {
{
"seed", &opt_seed, "Starting seed of the internal number generator", nullptr,
ARGTYPE_INT, "1", nullptr, nullptr
},
+ {
+ "nodelay", &opt_nodelay, "Output realtime points without delay", nullptr,
+ ARGTYPE_BOOL, ARG_NOMINMAX, nullptr
+ },
ARG_TERMINATOR
};
+// this generator is invariant across platforms.
+static std::mt19937* generator;
+
+// we do this cheesy distribution function because we need it to be invariant across platforms.
+// note uniform_int_distribution is not invariant.
+template <typename T>
+static T
+rand_num(const T max)
+{
+ T retval;
+ // scalefactor expression assumes generator is mt19937.
+ constexpr double scalefactor = 1.0 / std::mt19937::max();
+ do {
+ retval = static_cast<T>(static_cast<double>(max) * scalefactor * (*generator)());
+ } while (retval >= max);
+ return retval;
+}
static double
rand_dbl(const double max)
{
- return max * rand() / (((double)RAND_MAX) + 1);
+ return rand_num(max);
+}
+
+static float
+rand_flt(const float max)
+{
+ return rand_num(max);
}
static int
rand_int(const int max)
{
- return (int)((double)max * rand() / (((double)RAND_MAX) + 1));
+ return rand_num(max);
}
/* rand_str always returns a valid string with len >= 0 */
{
int len = rand_int(maxlen) + 1;
- char* res = (char*) xmalloc(len + 1);
+ auto res = (char*) xmalloc(len + 1);
res[len] = '\0';
for (int i = 0; i < len; i++) {
static void
random_rd_init(const QString&)
{
+ generator = new std::mt19937;
+ if (opt_seed) {
+ generator->seed(atoi(opt_seed));
+ } else {
+ generator->seed(gpsbabel_now);
+ }
}
static void
random_rd_deinit()
{
+ delete generator;
}
-static void
-random_read()
-{
#define RND(a) (rand_int(a) > 0)
- route_head* head;
- Waypoint* prev = nullptr;
- time_t time = gpsbabel_time;
-
- if (opt_seed) {
- srand(atoi(opt_seed));
- } else {
- srand(gpsbabel_now);
- }
-
-
- int points = (opt_points) ? atoi(opt_points) : rand_int(128) + 1;
- if (doing_trks || doing_rtes) {
- head = route_head_alloc();
- if (doing_trks) {
- head->rte_name = rand_qstr(8, "Trk_%s");
- track_add_head(head);
- } else {
- head->rte_name = rand_qstr(8, "Rte_%s");
- route_add_head(head);
- }
- head->rte_desc = rand_qstr(16, nullptr);
- if RND(3) {
- head->rte_urls.AddUrlLink(UrlLink(rand_qstr(8, "http://rteurl.example.com/%s")));
- }
- } else {
- head = nullptr;
- }
-
- for (int i = 0; i < points; i++) {
- Waypoint* wpt = new Waypoint;
+static Waypoint*
+random_generate_wpt(int i, const QDateTime& time, const Waypoint* prev)
+{
+ auto wpt = new Waypoint;
garmin_fs_t* gmsd = garmin_fs_alloc(-1);
fs_chain_add(&wpt->fs, (format_specific_data*) gmsd);
wpt->shortname = rand_qstr(8, "Wpt_%s");
} while (wpt->shortname == nullptr);
- wpt->latitude = rand_dbl(180) - 90;
- wpt->longitude = rand_dbl(360) - 180;
+ wpt->latitude = rand_dbl(180.0) - 90.0;
+ wpt->longitude = rand_dbl(360.0) - 180.0;
/* !!! "if RND(3) ..." produces some leaks in generated data !!! */
if RND(3) {
- wpt->altitude = rand_int(1000) / 10;
+ wpt->altitude = rand_dbl(100.0);
}
if RND(3) {
- WAYPT_SET(wpt, temperature, rand_int(320) / 10.0);
+ WAYPT_SET(wpt, temperature, rand_flt(32.0f));
}
if RND(3) {
- WAYPT_SET(wpt, proximity, rand_int(10000) / 10.0);
+ WAYPT_SET(wpt, proximity, rand_dbl(1000.0));
}
if RND(3) {
- WAYPT_SET(wpt, depth, rand_int(10000) / 10.0);
+ WAYPT_SET(wpt, depth, rand_dbl(1000.0));
}
if RND(3) {
wpt->AddUrlLink(rand_qstr(8, "http://link1.example.com/%s"));
}
wpt->SetCreationTime(time);
- if RND(3) {
- wpt->creation_time = wpt->creation_time.addMSecs(rand_int(1000));
- }
- time += rand_int(10) + 1;
- if (doing_trks) {
+ if (doing_trks || doing_posn) {
if (i > 0) {
- wpt->latitude = prev->latitude + (rand_dbl(1) / 1000);
- wpt->longitude = prev->longitude + (rand_dbl(1) / 1000);
+ wpt->latitude = prev->latitude + rand_dbl(0.001);
+ wpt->longitude = prev->longitude + rand_dbl(0.001);
WAYPT_SET(wpt, course, waypt_course(prev, wpt));
WAYPT_SET(wpt, speed, waypt_speed(prev, wpt));
}
wpt->sat = rand_int(12 + 1);
- wpt->hdop = (rand_int(500)) / 10.0;
- wpt->vdop = (rand_int(500)) / 10.0;
- wpt->pdop = (rand_int(500)) / 10.0;
+ wpt->hdop = rand_flt(50.0f);
+ wpt->vdop = rand_flt(50.0f);
+ wpt->pdop = rand_flt(50.0f);
wpt->fix = (fix_type)(rand_int(6) - 1);
if RND(3) {
wpt->cadence = rand_int(255);
}
} else {
if (doing_rtes && (i > 0)) {
- wpt->latitude = prev->latitude + (rand_dbl(1) / 100);
- wpt->longitude = prev->longitude + (rand_dbl(1) / 100);
+ wpt->latitude = prev->latitude + rand_dbl(0.01);
+ wpt->longitude = prev->longitude + rand_dbl(0.01);
}
if RND(3) {
wpt->description = rand_qstr(16, "Des_%s");
}
}
+ return wpt;
+}
+
+static void
+random_read()
+{
+
+ route_head* head;
+ Waypoint* prev = nullptr;
+ QDateTime time = QDateTime::fromTime_t(gpsbabel_time);
+
+ int points = (opt_points) ? atoi(opt_points) : rand_int(128) + 1;
+ if (doing_trks || doing_rtes) {
+ head = route_head_alloc();
+ if (doing_trks) {
+ head->rte_name = rand_qstr(8, "Trk_%s");
+ track_add_head(head);
+ } else {
+ head->rte_name = rand_qstr(8, "Rte_%s");
+ route_add_head(head);
+ }
+ head->rte_desc = rand_qstr(16, nullptr);
+ if RND(3) {
+ head->rte_urls.AddUrlLink(UrlLink(rand_qstr(8, "http://rteurl.example.com/%s")));
+ }
+ } else {
+ head = nullptr;
+ }
+
+ for (int i = 0; i < points; i++) {
+ Waypoint* wpt = random_generate_wpt(i, time, prev);
if (doing_trks) {
track_add_wpt(head, wpt);
} else if (doing_rtes) {
waypt_add(wpt);
}
+ time = time.addMSecs(1000 + rand_int(10000));
prev = wpt;
}
}
+struct realtime_data {
+ QDateTime time;
+ int points{-1};
+ int point_count{0};
+ Waypoint prev;
+};
+static realtime_data* realtime;
+
+void
+random_rd_posn_init(const QString&)
+{
+ generator = new std::mt19937;
+ if (opt_seed) {
+ generator->seed(atoi(opt_seed));
+ } else {
+ generator->seed(gpsbabel_now);
+ }
+ realtime = new realtime_data;
+ if (opt_points) {
+ realtime->points = atoi(opt_points);
+ }
+ realtime->time = QDateTime::fromTime_t(gpsbabel_time);
+}
+
+void
+random_rd_posn_deinit()
+{
+ delete generator;
+ delete realtime;
+}
+
+static Waypoint*
+random_rd_posn(posn_status* p_status)
+{
+ Waypoint* wpt = random_generate_wpt(realtime->point_count, realtime->time, &(realtime->prev));
+
+ if (p_status && (realtime->points > 0) && (realtime->point_count >= realtime->points)) {
+ p_status->request_terminate = 1;
+ }
+ ++realtime->point_count;
+
+ int delta_msecs= 1000 + rand_int(1000);
+ realtime->time = realtime->time.addMSecs(delta_msecs);
+ if (!opt_nodelay) {
+ QThread::msleep(delta_msecs);
+ }
+
+ // copy the waypoint as main will delete the returned waypt
+ // after write and we need it to generate the next wpt to
+ // simulate realtime tracking data.
+ realtime->prev = *wpt;
+
+ return wpt;
+}
ff_vecs_t random_vecs = {
ff_type_internal,
nullptr, /* write */
nullptr, /* exit */
random_args,
- CET_CHARSET_ASCII, 1 /* fixed */
- , NULL_POS_OPS,
+ CET_CHARSET_ASCII, 1, /* fixed */
+ {
+ random_rd_posn_init, random_rd_posn, random_rd_posn_deinit,
+ nullptr, nullptr, nullptr,
+ },
nullptr
};
--- /dev/null
+-28.606309,41.491196,85.918,Wpt_RD,1970-01-01T00:00:00Z
+-28.605513,41.492136,,Wpt_lBahVv7,1970-01-01T00:00:01.745Z
+-28.604906,41.492637,31.126,Wpt_hTE,1970-01-01T00:00:03.253Z
+-28.604548,41.493038,,Wpt_0H,1970-01-01T00:00:04.655Z
+-28.604396,41.493069,24.212,Wpt_k,1970-01-01T00:00:06.328Z
+-28.603524,41.493167,5.795,Wpt_iX,1970-01-01T00:00:07.835Z
+-28.603490,41.494039,36.201,Wpt_TyhlOke,1970-01-01T00:00:09.090Z
+-28.602885,41.494402,73.608,Wpt_rS,1970-01-01T00:00:10.507Z
+-28.602833,41.494822,2.947,Wpt_obZdF3b0,1970-01-01T00:00:11.965Z
+-28.601890,41.495138,,ESTIMATED Position,1970-01-01T00:00:13.543Z
--- /dev/null
+
+echo 'DESCRIPTION realtime tracking 1' >>${TMPDIR}/realtime1.style
+echo 'EXTENSION csv' >>${TMPDIR}/realtime1.style
+echo 'FIELD_DELIMITER COMMA' >>${TMPDIR}/realtime1.style
+echo 'RECORD_DELIMITER NEWLINE' >>${TMPDIR}/realtime1.style
+echo 'IFIELD LON_DECIMAL,"","%f"' >>${TMPDIR}/realtime1.style
+echo 'IFIELD LAT_DECIMAL,"","%f"' >>${TMPDIR}/realtime1.style
+echo 'IFIELD ALT_METERS,"","%.3f"' >>${TMPDIR}/realtime1.style
+echo 'IFIELD SHORTNAME,"","%s"' >>${TMPDIR}/realtime1.style
+echo 'IFIELD ISO_TIME_MS,"","%s"' >>${TMPDIR}/realtime1.style
+# test real time tracking
+gpsbabel -T -i random,points=10,seed=22,nodelay -f dummy -o xcsv,style=${TMPDIR}/realtime1.style -F ${TMPDIR}/realtime.csv
+compare ${REFERENCE}/realtime.csv ${TMPDIR}/realtime.csv
+
+
if (buf[jj] == 0) {
- printf("Found unexpected ZERO\n");
- exit(1);
+ fatal(MYNAME ": Found unexpected ZERO\n");
}
if (latscale == 0 || lonscale == 0) {
- printf("Found bad scales lonscale=0x%x latscale=0x%x\n", lonscale, latscale);
- exit(1);
+ fatal(MYNAME ": Found bad scales lonscale=0x%x latscale=0x%x\n", lonscale, latscale);
}
lon+=lonscale*scarray[buf[jj]>>4];
cbuf = buf;
}
- while ((s = csv_lineparse(cbuf, unicsv_fieldsep, "\"", 0)), !s.isEmpty()) {
+ while ((s = csv_lineparse(cbuf, unicsv_fieldsep, "\"", 0)), !s.isNull()) {
s = s.trimmed();
field_t* f = &fields_def[0];
vecs_t**
sort_and_unify_vecs(int* ctp)
{
- int vc;
+ size_t vc;
vecs_t** svp;
#if CSVFMTS_ENABLED
#endif
}
memset(&svp[i]->vec->cap, 0, sizeof(svp[i]->vec->cap));
switch (xcsv_file.datatype) {
- case 0:
+ case unknown_gpsdata:
case wptdata:
svp[i]->vec->cap[ff_cap_rw_wpt] = (ff_cap)(ff_cap_read | ff_cap_write);
break;
}
const char*
-name_option(long type)
+name_option(uint32_t type)
{
const char* at[] = {
"unknown",
*/
-#include "defs.h"
-#include "cet_util.h"
-#include "garmin_fs.h"
-#include "grtcirc.h"
-#include "session.h"
-#include "src/core/logging.h"
+#include <cmath> // for fabs
+#include <cstdio> // for printf, fflush, fprintf, stdout
+#include <ctime> // for time_t
+
+#include <QtCore/QByteArray> // for QByteArray
+#include <QtCore/QDateTime> // for QDateTime
#include <QtCore/QDebug>
-#include <QtCore/QList>
-#include <cmath>
-#include <cstdio>
+#include <QtCore/QList> // for QList
+#include <QtCore/QString> // for QString, operator==
+#include <QtCore/QTime> // for QTime
+#include <QtCore/QtGlobal> // for qPrintable
+
+#include "defs.h"
+#include "garmin_fs.h" // for garmin_ilink_t, garmin_fs_s, GMSD_FIND, garmin_fs_p
+#include "grtcirc.h" // for RAD, gcdist, heading_true_degrees, radtometers
+#include "queue.h" // for queue, QUEUE_INIT, dequeue, QUEUE_FOR_EACH, QUEUE_MOVE, ENQUEUE_TAIL
+#include "session.h" // for curr_session, session_t
+#include "src/core/datetime.h" // for DateTime
+#include "src/core/logging.h" // for Warning, Fatal
#if NEWQ
QList<Waypoint*> waypt_list;
{
waypt_init_bounds(bounds);
#if NEWQ
- foreach(Waypoint* waypointp, waypt_list) {
+ foreach (Waypoint* waypointp, waypt_list) {
#else
queue* elem, *tmp;
QUEUE_FOR_EACH(&waypt_head, elem, tmp) {
- Waypoint* waypointp = reinterpret_cast<Waypoint *>(elem);
+ Waypoint* waypointp = reinterpret_cast<Waypoint*>(elem);
#endif
waypt_add_to_bounds(bounds, waypointp);
}
find_waypt_by_name(const QString& name)
{
#if NEWQ
- foreach(Waypoint* waypointp, waypt_list) {
+ foreach (Waypoint* waypointp, waypt_list) {
#else
queue* elem, *tmp;
QUEUE_FOR_EACH(&waypt_head, elem, tmp) {
- Waypoint* waypointp = reinterpret_cast<Waypoint *>(elem);
+ Waypoint* waypointp = reinterpret_cast<Waypoint*>(elem);
#endif
if (waypointp->shortname == name) {
return waypointp;
queue* elem, *tmp;
QUEUE_FOR_EACH(head, elem, tmp) {
- Waypoint* q = reinterpret_cast<Waypoint *>(dequeue(elem));
+ Waypoint* q = reinterpret_cast<Waypoint*>(dequeue(elem));
delete q;
if (head == &waypt_head) {
waypt_ct--;
waypt_ct = 0;
QUEUE_FOR_EACH(qbackup, elem, tmp) {
- wpt = reinterpret_cast<Waypoint *>(elem);
+ wpt = reinterpret_cast<Waypoint*>(elem);
waypt_add(new Waypoint(*wpt));
no++;
}
}
double altitude = A->altitude - B->altitude;
- if (altitude == 0 ||
+ if (altitude == 0 ||
A->altitude == unknown_alt || B->altitude == unknown_alt) {
return 0;
}
// note: extra_data is not deep copied.
}
+Waypoint& Waypoint::operator=(const Waypoint& rhs)
+{
+ if (this != &rhs) {
+
+ // deallocate
+ if (gc_data != &Waypoint::empty_gc_data) {
+ delete gc_data;
+ }
+ fs_chain_destroy(fs);
+
+ // allocate and copy
+ // Q(rhs.Q),
+ latitude = rhs.latitude;
+ longitude = rhs.longitude;
+ altitude = rhs.altitude;
+ geoidheight = rhs.geoidheight;
+ depth = rhs.depth;
+ proximity = rhs.proximity;
+ shortname = rhs.shortname;
+ description = rhs.description;
+ notes = rhs.notes;
+ urls = rhs.urls;
+ wpt_flags = rhs.wpt_flags;
+ icon_descr = rhs.icon_descr;
+ creation_time = rhs.creation_time;
+ route_priority = rhs.route_priority;
+ hdop = rhs.hdop;
+ vdop = rhs.vdop;
+ pdop = rhs.pdop;
+ course = rhs.course;
+ speed = rhs.speed;
+ fix = rhs.fix;
+ sat = rhs.sat;
+ heartrate = rhs.heartrate;
+ cadence = rhs.cadence;
+ power = rhs.power;
+ temperature = rhs.temperature;
+ odometer_distance = rhs.odometer_distance;
+ gc_data = rhs.gc_data;
+ fs = rhs.fs;
+ session = rhs.session;
+ extra_data = rhs.extra_data;
+ // deep copy geocache data unless it is the specail static empty_gc_data.
+ if (rhs.gc_data != &Waypoint::empty_gc_data) {
+ gc_data = new geocache_data(*rhs.gc_data);
+ }
+
+ /*
+ * It's important that this duplicated waypoint not appear
+ * on the master Q.
+ */
+ QUEUE_INIT(&Q);
+
+ // deep copy fs chain data.
+ fs = fs_chain_copy(rhs.fs);
+
+ // note: session is not deep copied.
+ // note: extra_data is not deep copied.
+ }
+
+ return *this;
+}
+
bool
Waypoint::HasUrlLink() const
{
/* ALTITUDE CONVERSIONS**********************************************/
case XT_ALT_FEET:
/* altitude in feet as a decimal value */
- buff = QString().sprintf(fmp.printfc.constData(),
- METERS_TO_FEET(wpt->altitude));
+ if (wpt->altitude != unknown_alt) {
+ buff = QString().sprintf(fmp.printfc.constData(),
+ METERS_TO_FEET(wpt->altitude));
+ }
break;
case XT_ALT_METERS:
/* altitude in meters as a decimal value */
- buff = QString().sprintf(fmp.printfc.constData(),
- wpt->altitude);
+ if (wpt->altitude != unknown_alt) {
+ buff = QString().sprintf(fmp.printfc.constData(),
+ wpt->altitude);
+ }
break;
/* DISTANCE CONVERSIONS**********************************************/